import * as Cesium from '@cesiumjs';
import CustomGroundRectangle from "../../../../utils/CustomGroundRectangle.js"
import getGridDataFromKriging from "./kriging/getGridDataFromKriging.js"
import {
  interpolateGridData,
  interpolateGridData2
} from "./interpolateGridData.js"

var g_ctx = void 0;

function getColorPalette(gradient, result) {
  if (result) {
    if (!result instanceof Uint8ClampedArray) {
      throw new Error('result类型不对！');
    }
    if (result.length !== 256 * 4) {
      throw new Error('result的数组长度不对，必须为256！');
    }
  }

  if (!g_ctx) {
    var paletteCanvas = document.createElement('canvas');
    var paletteCtx = paletteCanvas.getContext('2d');
    paletteCanvas.width = 256;
    paletteCanvas.height = 1;
    g_ctx = paletteCtx;
  }

  var lg = g_ctx.createLinearGradient(0, 0, 256, 1);
  gradient.forEach(function(e) {
    lg.addColorStop(e[0], e[1]);
  });

  g_ctx.clearRect(0, 0, 256, 1);
  g_ctx.fillStyle = lg;
  g_ctx.fillRect(0, 0, 256, 1);

  var data = g_ctx.getImageData(0, 0, 256, 1).data;

  if (!result) {
    result = new Uint8ClampedArray(data);
  } else {
    data.forEach(function(e, i) {
      return result[i] = e;
    });
  }

  return result;
};

function getColorFromColorPalette(ratio, palette, result) {
  // const value = element.value < min ? min : (element.value > max ? max : element.value);
  // const offset = (255 * (value - min) / (max - min)) | 0; // 256会导致1.0的值错误
  var min = 0,
    max = 1;

  ratio = ratio < min ? min : ratio > max ? max : ratio;
  var offset = 255 * ratio | 0;

  var red = palette[offset * 4];
  var green = palette[offset * 4 + 1];
  var blue = palette[offset * 4 + 2];
  var alpha = palette[offset * 4 + 3];

  if (!result) {
    result = [255, 255, 255, 255];
  }

  result[0] = red;
  result[1] = green;
  result[2] = blue;
  result[3] = alpha;

  return result;
}

var setImageDataFunc = void 0;

const defaultOptions = {
  /**
   * @description 位置数组 [经度、纬度、高度]
   * @type {array}
   * @instance
   * @default [0, 0, 0]
   * @memberof Obj.HeatMap
   */
  position: [0, 0, 0],
  /**
   * 宽度
   * @type {number}
   * @instance
   * @default 100
   * @memberof Obj.HeatMap
   */
  width: 100,
  /**
   * 高度
   * @type {number}
   * @instance
   * @default 100
   * @memberof Obj.HeatMap
   */
  height: 100,
  /**
   * @description 原点
   * @type {array}
   * @instance
   * @default [0.5, 0.5]
   * @memberof Obj.HeatMap
   */
  origin: [0.5, 0.5],
  /**
   * @description 旋转角
   * @type {number}
   * @instance
   * @default 0
   * @memberof Obj.HeatMap
   */
  rotation: 0.0,
  /**
   * 显示
   * @type {boolean}
   * @instance
   * @default true
   * @memberof Obj.HeatMap
   */
  show: true,
  /**
   * 调色板，形式如 [[x, y], [x1, y1], ...] x为数字，0-1之间；y表示颜色的字符串形式
   * @type {array}
   * @instance
   * @default [[0, 'green'], [0.2, 'blue'], [0.6, 'yellow'], [1.0, 'red']]
   * @memberof Obj.HeatMap
   * @example
   * xxx.gradient = [[0, 'green'], [0.2, 'blue'], [0.6, 'yellow'], [1.0, 'red']];
   */
  gradient: [
    [0, 'green'],
    [0.2, 'blue'],
    [0.6, 'yellow'],
    [1.0, 'red']
  ],
  /**
   * 网格数据最小值
   * @type {number}
   * @instance
   * @default 0
   * @memberof Obj.HeatMap
   */
  minValue: 0,
  /**
   * 网格数据最大值
   * @type {number}
   * @instance
   * @default 1
   * @memberof Obj.HeatMap
   */
  maxValue: 1,
  /**
   * 网格数据宽度
   * @type {number}
   * @instance
   * @default 100
   * @memberof Obj.HeatMap
   */
  dataWidth: 100,
  /**
   * 网格数据高度
   * @type {number}
   * @instance
   * @default 100
   * @memberof Obj.HeatMap
   */
  dataHeight: 100
};

class HeatMap {
  constructor(viewer, options) {
    this.viewer = viewer;
    this.options = {
      ...defaultOptions,
      ...options
    }

    this._imageData = undefined;
    this._colorPalette = new Uint8ClampedArray(256 * 4);
    this._colorPalette.fill(255);

    this.init();
  }

  init() {
    const _this = this;
    _this._customGroundRectangle = new CustomGroundRectangle(_this.viewer, this.options);
    _this.updateGroundRectangle()
    _this.updateColorPalette()
    // _this.updateColorPalette()
  }

  updateGroundRectangle() {
    const _this = this;
    const options = this.options
    var cgr = _this._customGroundRectangle;
    cgr.position = options.position;
    cgr.width = options.width;
    cgr.height = options.height;

    if (cgr.canvasWidth !== options.dataWidth || cgr.canvasHeight !== options.dataHeight) {
      cgr.canvasWidth = options.dataWidth;
      cgr.canvasHeight = options.dataHeight;
      cgr.drawCanvas(function(ctx) {
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, options.dataWidth, options.dataHeight);
      });
    }
  };

  updateColorPalette() {
    const options = this.options
    getColorPalette(options.gradient, this._colorPalette);
  };

  setGridData(gridData) {
    var _this2 = this;
    const options = this.options

    const {
      dataWidth,
      dataHeight,
      maxValue,
      minValue
    } = options;

    var data = gridData;
    if (data && data.length && data.length === dataWidth * dataHeight) {
      if (!this._imageData || this._imageData.width !== dataWidth || this._imageData.height !== dataHeight) {
        this._imageData = new ImageData(dataWidth, dataHeight);
      }

      var valueRange = maxValue - minValue;
      var color = [255, 255, 255, 255];
      // var dataHeight = this.dataHeight;
      // var dataWidth = this.dataWidth;
      var imageData = this._imageData.data;
      // var minValue = minValue;
      var colorPalette = this._colorPalette;

      // 为了性能提升，用eval的方式来替代
      // valueRange
      // getColorFromColorPalette
      // for (let j=0; j<dataHeight; ++j) {
      //     for (let i=0; i<dataWidth; ++i) {
      //         const v = data[j*dataWidth+i];
      //         const ratio = (v - minValue) / valueRange;
      //         const c = getColorFromColorPalette(ratio, colorPalette, color);
      //         if (c) {
      //              const offset = (j*dataWidth+i) * 4;
      //              imageData[offset + 0] = c[0];
      //              imageData[offset + 1] = c[1];
      //              imageData[offset + 2] = c[2];
      //              imageData[offset + 3] = c[3];
      //         }
      //     }
      // }
      if (!setImageDataFunc) {
        var evalString = `\n
          for (let j=0; j<dataHeight; ++j) {\n
            for (let i=0; i<dataWidth; ++i) {\n
              const v = data[j*dataWidth+i];\n
              const ratio = (v - minValue) / valueRange;\n
              const c = getColorFromColorPalette(ratio, colorPalette, color);\n
              if (c) {\n
                const offset = (j*dataWidth+i) * 4;\n
                imageData[offset + 0] = c[0];\n
                imageData[offset + 1] = c[1];\n
                imageData[offset + 2] = c[2];\n
                imageData[offset + 3] = c[3];\n
              }\n
            }\n
          }`;
        var evalWrapString = `\n
          return (function(data, valueRange, color, dataHeight, dataWidth, imageData, minValue, colorPalette, getColorFromColorPalette){
            ${evalString}
          })`;
        setImageDataFunc = Function(evalWrapString)();
      }
      setImageDataFunc(data, valueRange, color, dataHeight, dataWidth, imageData, minValue,
        colorPalette, getColorFromColorPalette);

      var cgr = this._customGroundRectangle;
      cgr.canvasWidth = dataWidth;
      cgr.canvasHeight = dataHeight;
      cgr.drawCanvas(function(ctx) {
        // 是否有必要？
        // ctx.clearRect(0, 0, this.dataWidth, this.dataHeight);
        ctx.putImageData(_this2._imageData, 0, 0);
      });
    } else {
      // const cgr = this._customGroundRectangle;
      // cgr.drawCanvas(ctx => {
      //     ctx.fillStyle = 'white';
      //     ctx.fillRect(0, 0, this.dataWidth, this.dataHeight);
      // });

      var _cgr = this._customGroundRectangle;
      _cgr.canvasWidth = dataWidth;
      _cgr.canvasHeight = dataHeight;
      _cgr.drawCanvas(function(ctx) {
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, dataWidth, dataHeight);
      });
    }
  }

  copyfromOtherCanvas(canvas) {

    const {
      dataWidth,
      dataHeight,
    } = this.options;

    if (canvas.width !== dataWidth || canvas.height !== dataHeight) {
      console.error('canvas尺寸一致！');
      return;
    }
    const cgr = this._customGroundRectangle
    cgr && cgr._texture && cgr._texture.copyFrom(canvas);
  }

  flyTo(options) {

    const {
      duration,
      complete
    } = (options || {})

    const {
      position,
      width,
    } = this.options;

    const [x, y, z] = position;
    const destination = Cesium.Cartesian3.fromRadians(x, y, z);

    // this.viewer.camera.flyTo(position, width, [0, -Math.PI / 3, 0]);
    this.viewer.scene.camera.flyTo({
      duration,
      complete,
      destination,
      // destination: Cesium.Cartesian3.fromDegrees(-74.019, 40.6912, 750),
      orientation: {
        heading: Cesium.Math.toRadians(0),
        pitch: Cesium.Math.toRadians(-90)
      }
    });
  }
}

HeatMap.defaultOptions = defaultOptions;

HeatMap.getGridDataFromKriging = getGridDataFromKriging;

HeatMap.interpolateGridData = interpolateGridData;
HeatMap.interpolateGridData2 = interpolateGridData2;

export default HeatMap;
